package com.xes.attend.rd60n;

import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import com.xes.attend.domain.AttendVo;
import com.xes.attend.domain.Result;
import com.xes.attend.domain.ResultCode;
import com.xes.attend.rd60n.jiecard.cn.*;
import com.xes.attend.rd60n.utils.StringUtils;
import com.xes.attend.server.AdminController;
import com.xes.attend.utils.HttpClientUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.util.UriTemplate;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;


import struct.JavaStruct;
import struct.StructException;

class TCPServerEvent implements TCPServerCallback {

	private static final Logger log = LogManager.getLogger("TCPServerEvent");

	private static final int SHOW_LENGTH = 16;
	private static final String READ_CARD_URL = "http://localhost:8100/attend/card/query/{cardNum}";

	public static String toHex(byte[] src) {
		StringBuilder stringBuilder = new StringBuilder("");
		if (src == null || src.length <= 0) {
			return null;
		}
		for (int i = 0; i < src.length; i++) {
			int v = src[i] & 0xFF;
			String hv = Integer.toHexString(v);
			if (hv.length() < 2) {
				stringBuilder.append(0);
			}
			stringBuilder.append(hv);
		}
		return stringBuilder.toString();
	}

	/**
	 * 刷卡器显示
	 * 
	 * @param msg
	 *            显示的内容
	 * @param beep
	 *            蜂鸣次数
	 * @throws InterruptedException
	 */
	public static void display(RD60N dev, String[] msg, int beep) throws InterruptedException {
		for (int i = 0; i < msg.length; i++) {
			msg[i] = StringUtils.fixSubString(msg[i], SHOW_LENGTH);
			dev.rf_display((byte) (i + 1), msg[i], (byte) 2);
		}
		for (int i = 0; i < beep; i++) {
			dev.rf_beep((byte) 10);
			Thread.sleep(200);
		}
	}

	/**
	 * 回调函数
	 */
	@Override
	public void DeviceCallback(NetConn conn, CmdData cmd_data) {
		// 刷卡后自动调用
		// 注意：此方法是在一个线程中运行的，请注意多线程同步的问题

		RD60N dev = new RD60N();
		dev.rf_open(conn);
		if (cmd_data.cmd_id == CmdData.CMD_ID_CARD_AUTO_UP) {
			CmdParamCardActive param = new CmdParamCardActive();
			try {
				byte[] card_data = new byte[16];
				byte[] password = new byte[6];
				int card_read_ok = 0;
				String card_num = new String();
				AttendVo attend_data = null;
				Result<AttendVo> result = null;

				for (int i = 0; i < 6; ++i) {
					password[i] = (byte) 0xff;
				}

				JavaStruct.unpack(param, cmd_data.data);

				do {
					// 先停止自动寻卡
					dev.rf_card_confirm(param.card_sn, (byte) 0);

					// 验证A密码，0扇区
					if (0 != dev.rf_authent((byte) 0x60, param.card_sn, (byte) 0, password)) {
						log.error("密码认证失败");
						break;
					}

					// 读取block1的数据
					if (0 != dev.rf_read((byte) 1, card_data)) {
						log.error("读取块1数据失败");
						break;
					}

					card_num = new String(card_data);
					card_num = card_num.replace("\0", "");

					log.info("读取卡号[" + card_num + "]");

					// 读取卡号正常有15个字节
					if (card_num.length() == SHOW_LENGTH - 1) {

						Map<String, String> vars = ImmutableMap.of("cardNum", card_num);
						ObjectMapper objectMapper = new ObjectMapper();
						objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
						result = null;

						URI expandUri = new UriTemplate(READ_CARD_URL).expand(vars);
						String responseBody = HttpClientUtil.httpGet(expandUri.toString(), null, null);
						try {
							result = objectMapper.readValue(responseBody, new TypeReference<Result<AttendVo>>() {
							});
							card_read_ok = result.getCode();

							log.info("获取刷卡考勤：" + result.toString());

							if (result.isSuccess()) {
								// log.info(result.getData());
								attend_data = result.getData();
							} else {
								log.info(result.getMessage());
							}

						} catch (IOException e) {
							log.error("获取刷卡考勤异常: " + e.getMessage());
						}

					} else {
						log.error("学员卡号异常");
					}

				} while (false);

				// 设置背光到80%，3秒后回复到1%
				dev.rf_set_lcd_backlight_temp((byte) 80, (byte) 1, (byte) 3);

				if (card_read_ok == 0) {
					display(dev, new String[] { "", "读卡数据失败", "请重试", "" }, 3);
				} else if (card_read_ok == ResultCode.SUCCESS.getCode()) {
					display(dev,
							new String[] { attend_data.getStuName() + result.getMessage(),
									attend_data.getClassRoomName(), attend_data.getTeacherName() + "老师",
									"第" + attend_data.getCurriculumNum() + "次课" },
							1);
				} else {
					display(dev, new String[] { "", result.getMessage(), result.getCode() + "", "" }, 3);
				}

				// 卡操作完成后，继续自动寻卡
				dev.rf_card_confirm(param.card_sn, (byte) 1);

			} catch (StructException e) {
				log.error(e.toString());
			} catch (InterruptedException e) {
				log.error(e.toString());
			}
		}
	}
}

public class JCRD60N {
	private static final Logger log = LogManager.getLogger("JCRD60N");

	public void run() {
		log.info("AttendClient(JCRD60N) start.");
		TCPServer serv = new TCPServer();
		TCPServerEvent callback = new TCPServerEvent();
		serv.StartServer(9100, callback);
	}

}